/*
 * playlist.cc
 *
 *  Created on: Sep 18, 2012
 *      Author: shaohong
 */

#include "playlist.hh"
#include <stdlib.h>

using namespace std;

/*The function reads the data of a new track from the parameter input stream,
 * creates a new Track and appends it to the parameter playlist (the new track
 * is added as the last track in the playlist).
 *
 * The input stream will feed data in the following format
 *  <Track name>
 * <Track artist>
 * <Track length>
 * */

void addTrack(std::list<Track>& playlist, std::istream& is) {
	Track newTrack;

	char line[256];
	is.getline(line, sizeof(line));

	if (is.eof()) {
		return;
	}
	newTrack.name = string(line);

	is.getline(line, sizeof(line));
	if (is.eof()) {
		return;
	}
	newTrack.artist = string(line);

	is.getline(line, sizeof(line));
	newTrack.length = atoi(line);


	playlist.push_back(newTrack);
}

bool isSameTrack(const Track& track1, const Track& track2) {
	if (track1.artist.compare(track2.artist) != 0) {
		return false;
	}

	if (track1.length != track2.length) {
		return false;
	}

	if (track1.name.compare(track2.name) != 0) {
		return false;
	}

	return true;
}

void removeTrack(std::list<Track>& playlist, const Track& track) {

	list<Track>::iterator itr = playlist.begin();
	while (itr != playlist.end()) {
		if (isSameTrack((*itr), track)) {
			playlist.erase(itr);
			return;
		}
		itr++;
	}

}

void printPlaylist(const std::list<Track>& playlist, std::ostream& os) {
	list<Track>::const_iterator itr = playlist.begin();
	while (itr != playlist.end()) {
		os << itr->name << " - " << itr->artist << " - " << itr->length
				<< " sec" << endl;
		++itr;
	}

}

bool sortingPredicate(const Track& l, const Track& r) {
//	* The function returns true if the track given as the first parameter is
//	 * "smaller", in other words, comes before the second parameter.
//	 *
//	 * As there can exist tracks with the same name, the function first compares the
//	 * tracks by their names, if the names are equal the function further compares
//	 * the artists. If even the artists are equal the function compares the lengths.
//
	if (l.name.compare(r.name) < 0) {
		return true;
	}

	if (l.name.compare(r.name) > 0) {
		return false;
	}

	// names are the same, compare the artists
	if (l.artist.compare(r.artist) < 0) {
		return true;
	}

	if (l.artist.compare(r.artist) > 0) {
		return false;
	}

	return (l.length <= r.length);

}

void sortPlaylist(std::list<Track>& playlist,
		bool(*predicate)(const Track& l, const Track& r)) {
	playlist.sort(predicate);
}

// check if the list contains the given track
bool contains(const std::list<Track>& playlist, const Track& track) {
	list<Track>::const_iterator itr = playlist.begin();
	while (itr != playlist.end()) {

		if (isSameTrack((*itr), track)) {
			return true;
		}
		itr++;
	}

	return false;
}

std::list<Track> mergeWithoutDuplicates(const std::list<Track>& l,
		const std::list<Track>& r) {
	list<Track> mergedList = list<Track>();

	list<Track>::const_iterator itr = l.begin();

	// put all things into merged list, throw away duplicates
	while (itr != l.end()) {
		Track candidateTrack = (*itr);
		if (!contains(mergedList, candidateTrack)) {
			mergedList.push_back(candidateTrack);
		}
		itr++;
	}

	itr = r.begin();
	while (itr != r.end()) {
		Track candidateTrack = (*itr);
		if (!contains(mergedList, candidateTrack)) {
			mergedList.push_back(candidateTrack);
		}
		itr++;
	}

	sortPlaylist((mergedList), sortingPredicate);

	return (mergedList);
}

